package org.eden.karb.device.audio.impl;

import cern.colt.list.IntArrayList;
import org.eden.karb.common.util.AudioUtils;
import org.eden.karb.device.MonitorDevice;
import org.eden.karb.event.EventDispatcher;
import org.eden.karb.event.impl.AudioMonitorEvent;
import org.eden.karb.event.impl.VoidEventParameters;
import org.jthompson.monsoon.annotations.Event;
import org.jthompson.monsoon.annotations.Event.EventType;

/**
 * Audio monitor device implementation.
 *
 * @author trsimoes
 */
public class AudioMonitorDeviceImpl extends AbstractAudioDeviceImpl implements MonitorDevice,
        EventDispatcher<AudioMonitorEvent, VoidEventParameters> {

    private IntArrayList levels;

    public AudioMonitorDeviceImpl() {
        this.levels = new IntArrayList();
    }

    @Override
    protected void execute(byte[] audioInBuffer, int numberOfBytesRead) {

        long executionTime = System.currentTimeMillis();

        if ((executionTime - this.lastEvent) >= configuration.getTimeBetweenEvents()) {
            // publish data
            publishEvent();
            // reset buffer
            this.levels = new IntArrayList();
            // set timestamp for last event
            this.lastEvent = executionTime;
        } else {
            int level = AudioUtils.calculateRMSLevel(audioInBuffer);
            this.levels.add(level);
        }
    }

    @Override
    protected void closeResources() throws Exception {
        configuration.getTargetRecordLine().close();
    }

    private void publishEvent() {
        if (this.levels.size() > 0) {
            publish(new VoidEventParameters());
        }
    }

    @Event(name = "audioMonitor", type = EventType.DISPATCHER)
    public AudioMonitorEvent publish(VoidEventParameters parameters) {
        AudioMonitorEvent event = new AudioMonitorEvent(getKey());
        event.setLevels(this.levels.elements());
        return event;
    }
}
